Skip to content

Conversation

harshanarayana
Copy link
Contributor

@harshanarayana harshanarayana commented Mar 1, 2021

What does this pull request do?

Replacement for #522

Related issues

closes #521

Todo

  • Unit Tests
  • Minor Refactoring
  • Documentation

@ghost
Copy link

ghost commented Mar 1, 2021

💔 Tests Failed

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview preview

Expand to view the summary

Build stats

  • Start Time: 2021-11-01T15:54:44.252+0000

  • Duration: 28 min 29 sec

  • Commit: 1ae5422

Test stats 🧪

Test Results
Failed 36
Passed 10135
Skipped 9369
Total 19540

Test errors 36

Expand to view the tests failures

> Show only the first 10 test failures

Initializing / Test / Python-python-3.7-2 / test_get[/-GET /-1-custom_context0] – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     url = '/', transaction_name = 'GET /', span_count = 1, custom_context = {}
    sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7fde0d7a8e60>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7fde0d9ef790>
    
        @pytest.mark.parametrize(
            "url, transaction_name, span_count, custom_context",
            [("/", "GET /", 1, {}), ("/greet/sanic", "GET /greet/<name:string>", 0, {"name": "sanic"})],
        )
        def test_get(url, transaction_name, span_count, custom_context, sanic_elastic_app, elasticapm_client):
    >       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client))
    
    tests/contrib/sanic/sanic_tests.py:45: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:109: in _generate
        @app.exception(ValueError)
    /home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7fde0fce73b0>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError 
    

Initializing / Test / Python-python-3.7-2 / test_get[/greet/sanic-GET /greet/<name:string>-0-custom_context1] – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     url = '/greet/sanic', transaction_name = 'GET /greet/<name:string>'
    span_count = 0, custom_context = {'name': 'sanic'}
    sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7fde0d73c050>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7fde0d8ddad0>
    
        @pytest.mark.parametrize(
            "url, transaction_name, span_count, custom_context",
            [("/", "GET /", 1, {}), ("/greet/sanic", "GET /greet/<name:string>", 0, {"name": "sanic"})],
        )
        def test_get(url, transaction_name, span_count, custom_context, sanic_elastic_app, elasticapm_client):
    >       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client))
    
    tests/contrib/sanic/sanic_tests.py:45: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:109: in _generate
        @app.exception(ValueError)
    /home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7fde0d73c200>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError 
    

Initializing / Test / Python-python-3.7-2 / test_capture_exception – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7fde0d73c4d0>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7fde0dac95d0>
    
        def test_capture_exception(sanic_elastic_app, elasticapm_client):
    >       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client))
    
    tests/contrib/sanic/sanic_tests.py:80: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:109: in _generate
        @app.exception(ValueError)
    /home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7fde0d73c8c0>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError 
    

Initializing / Test / Python-python-3.7-2 / test_unhandled_exception_capture – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7fde0d73cc20>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7fde0d9a3b50>
    
        def test_unhandled_exception_capture(sanic_elastic_app, elasticapm_client):
    >       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client))
    
    tests/contrib/sanic/sanic_tests.py:103: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:109: in _generate
        @app.exception(ValueError)
    /home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7fde0d73cef0>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError 
    

Initializing / Test / Python-python-3.7-2 / test_client_with_custom_error_handler[/raise-exception-custom-handler] – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     url = '/raise-exception', expected_source = 'custom-handler'
    sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7fde0d628290>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7fde0d8eae10>
    custom_error_handler = <tests.contrib.sanic.fixtures.CustomErrorHandler object at 0x7fde0d8eaa50>
    
        @pytest.mark.parametrize(
            "url, expected_source",
            [
                ("/raise-exception", "custom-handler"),
                ("/raise-value-error", "value-error-custom"),
                ("/fallback-value-error", "custom-handler-default"),
            ],
        )
        def test_client_with_custom_error_handler(
            url, expected_source, sanic_elastic_app, elasticapm_client, custom_error_handler
        ):
    >       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client, error_handler=custom_error_handler))
    
    tests/contrib/sanic/sanic_tests.py:134: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:109: in _generate
        @app.exception(ValueError)
    /home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7fde0d6285f0>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError 
    

Initializing / Test / Python-python-3.7-2 / test_client_with_custom_error_handler[/raise-value-error-value-error-custom] – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     url = '/raise-value-error', expected_source = 'value-error-custom'
    sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7fde0d6287a0>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7fde0d875610>
    custom_error_handler = <tests.contrib.sanic.fixtures.CustomErrorHandler object at 0x7fde0d875510>
    
        @pytest.mark.parametrize(
            "url, expected_source",
            [
                ("/raise-exception", "custom-handler"),
                ("/raise-value-error", "value-error-custom"),
                ("/fallback-value-error", "custom-handler-default"),
            ],
        )
        def test_client_with_custom_error_handler(
            url, expected_source, sanic_elastic_app, elasticapm_client, custom_error_handler
        ):
    >       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client, error_handler=custom_error_handler))
    
    tests/contrib/sanic/sanic_tests.py:134: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:109: in _generate
        @app.exception(ValueError)
    /home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7fde0d628c20>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError 
    

Initializing / Test / Python-python-3.7-2 / test_client_with_custom_error_handler[/fallback-value-error-custom-handler-default] – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     url = '/fallback-value-error', expected_source = 'custom-handler-default'
    sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7fde0d628dd0>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7fde0d8dead0>
    custom_error_handler = <tests.contrib.sanic.fixtures.CustomErrorHandler object at 0x7fde0d8deb90>
    
        @pytest.mark.parametrize(
            "url, expected_source",
            [
                ("/raise-exception", "custom-handler"),
                ("/raise-value-error", "value-error-custom"),
                ("/fallback-value-error", "custom-handler-default"),
            ],
        )
        def test_client_with_custom_error_handler(
            url, expected_source, sanic_elastic_app, elasticapm_client, custom_error_handler
        ):
    >       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client, error_handler=custom_error_handler))
    
    tests/contrib/sanic/sanic_tests.py:134: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:109: in _generate
        @app.exception(ValueError)
    /home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7fde0d630200>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError 
    

Initializing / Test / Python-python-3.7-2 / test_header_field_sanitization – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7fde0d6285f0>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7fde0d99ab10>
    
        def test_header_field_sanitization(sanic_elastic_app, elasticapm_client):
    >       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client))
    
    tests/contrib/sanic/sanic_tests.py:148: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:109: in _generate
        @app.exception(ValueError)
    /home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7fde0d628830>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError 
    

Initializing / Test / Python-python-3.7-2 / test_custom_callback_handlers – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7fde0d73cc20>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7fde0dac5310>
    
        def test_custom_callback_handlers(sanic_elastic_app, elasticapm_client):
            def _custom_transaction_callback(request):
                return "my-custom-name"
        
            async def _user_info_callback(request):
                return "test", "[email protected]", 1234356
        
            async def _label_callback(request):
                return {
                    "label1": "value1",
                    "label2": 19,
                }
        
            sanic_app, apm = next(
                sanic_elastic_app(
                    elastic_client=elasticapm_client,
                    transaction_name_callback=_custom_transaction_callback,
                    user_context_callback=_user_info_callback,
    >               label_info_callback=_label_callback,
                )
            )
    
    tests/contrib/sanic/sanic_tests.py:182: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:109: in _generate
        @app.exception(ValueError)
    /home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7fde0fce73b0>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError 
    

Initializing / Test / Python-python-3.10-rc-3 / test_get[/-GET /-1-custom_context0] – tests.contrib.sanic.sanic_tests
    Expand to view the error details

     TypeError: ElasticAPMPatchedErrorHandler.add() takes 3 positional arguments but 4 were given 
    

    Expand to view the stacktrace

     url = '/', transaction_name = 'GET /', span_count = 1, custom_context = {}
    sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7f27d4d68b80>
    elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7f27d4cf8b20>
    
        @pytest.mark.parametrize(
            "url, transaction_name, span_count, custom_context",
            [("/", "GET /", 1, {}), ("/greet/sanic", "GET /greet/<name:string>", 0, {"name": "sanic"})],
        )
        def test_get(url, transaction_name, span_count, custom_context, sanic_elastic_app, elasticapm_client):
    >       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client))
    
    tests/contrib/sanic/sanic_tests.py:45: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/contrib/sanic/fixtures.py:110: in _generate
        async def handle_value_error(request, exception):
    /home/user/.local/lib/python3.10/site-packages/sanic/mixins/exceptions.py:36: in decorator
        self._apply_exception_handler(future_exception)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = Sanic(name="elastic-apm-test-app")
    handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7f27d4d68d30>, exceptions=(<class 'ValueError'>,))
    route_names = None
    
        def _apply_exception_handler(
            self,
            handler: FutureException,
            route_names: Optional[List[str]] = None,
        ):
            """Decorate a function to be registered as a handler for exceptions
        
            :param exceptions: exceptions
            :return: decorated function
            """
        
            for exception in handler.exceptions:
                if isinstance(exception, (tuple, list)):
                    for e in exception:
                        self.error_handler.add(e, handler.handler, route_names)
                else:
    >               self.error_handler.add(exception, handler.handler, route_names)
    E               TypeError: ElasticAPMPatchedErrorHandler.add() takes 3 positional arguments but 4 were given
    
    /home/user/.local/lib/python3.10/site-packages/sanic/app.py:356: TypeError 
    

Steps errors 10

Expand to view the steps failures

Shell Script
  • Took 0 min 19 sec . View more details here
  • Description: ./tests/scripts/docker/run_tests.sh python-3.7 sanic-newest
Shell Script
  • Took 0 min 18 sec . View more details here
  • Description: ./tests/scripts/docker/run_tests.sh python-3.7 sanic-newest
Shell Script
  • Took 0 min 23 sec . View more details here
  • Description: ./tests/scripts/docker/run_tests.sh python-3.8 sanic-newest
Shell Script
  • Took 0 min 23 sec . View more details here
  • Description: ./tests/scripts/docker/run_tests.sh python-3.8 sanic-newest
Shell Script
  • Took 0 min 23 sec . View more details here
  • Description: ./tests/scripts/docker/run_tests.sh python-3.9 sanic-newest
Shell Script
  • Took 0 min 22 sec . View more details here
  • Description: ./tests/scripts/docker/run_tests.sh python-3.9 sanic-newest
Shell Script
  • Took 0 min 22 sec . View more details here
  • Description: ./tests/scripts/docker/run_tests.sh python-3.10-rc sanic-newest
Shell Script
  • Took 0 min 21 sec . View more details here
  • Description: ./tests/scripts/docker/run_tests.sh python-3.10-rc sanic-newest
Archive the artifacts
  • Took 0 min 0 sec . View more details here
  • Description: [2021-11-01T16:23:11.310Z] Archiving artifacts Python-python-3.7-sanic-newest tests failed : hudson
Error signal
  • Took 0 min 0 sec . View more details here
  • Description: Python-python-3.7-sanic-newest tests failed : hudson.AbortException: script returned exit code 2

🐛 Flaky test report

❕ There are test failures but not known flaky tests.

Expand to view the summary

Genuine test errors 36

💔 There are test failures but not known flaky tests, most likely a genuine test failure.

  • Name: Initializing / Test / Python-python-3.7-2 / test_get[/-GET /-1-custom_context0] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.7-2 / test_get[/greet/sanic-GET /greet/<name:string>-0-custom_context1] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.7-2 / test_capture_exception – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.7-2 / test_unhandled_exception_capture – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.7-2 / test_client_with_custom_error_handler[/raise-exception-custom-handler] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.7-2 / test_client_with_custom_error_handler[/raise-value-error-value-error-custom] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.7-2 / test_client_with_custom_error_handler[/fallback-value-error-custom-handler-default] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.7-2 / test_header_field_sanitization – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.7-2 / test_custom_callback_handlers – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.10-rc-3 / test_get[/-GET /-1-custom_context0] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.10-rc-3 / test_get[/greet/sanic-GET /greet/<name:string>-0-custom_context1] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.10-rc-3 / test_capture_exception – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.10-rc-3 / test_unhandled_exception_capture – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.10-rc-3 / test_client_with_custom_error_handler[/raise-exception-custom-handler] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.10-rc-3 / test_client_with_custom_error_handler[/raise-value-error-value-error-custom] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.10-rc-3 / test_client_with_custom_error_handler[/fallback-value-error-custom-handler-default] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.10-rc-3 / test_header_field_sanitization – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.10-rc-3 / test_custom_callback_handlers – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.9-2 / test_get[/-GET /-1-custom_context0] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.9-2 / test_get[/greet/sanic-GET /greet/<name:string>-0-custom_context1] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.9-2 / test_capture_exception – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.9-2 / test_unhandled_exception_capture – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.9-2 / test_client_with_custom_error_handler[/raise-exception-custom-handler] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.9-2 / test_client_with_custom_error_handler[/raise-value-error-value-error-custom] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.9-2 / test_client_with_custom_error_handler[/fallback-value-error-custom-handler-default] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.9-2 / test_header_field_sanitization – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.9-2 / test_custom_callback_handlers – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.8-3 / test_get[/-GET /-1-custom_context0] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.8-3 / test_get[/greet/sanic-GET /greet/<name:string>-0-custom_context1] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.8-3 / test_capture_exception – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.8-3 / test_unhandled_exception_capture – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.8-3 / test_client_with_custom_error_handler[/raise-exception-custom-handler] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.8-3 / test_client_with_custom_error_handler[/raise-value-error-value-error-custom] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.8-3 / test_client_with_custom_error_handler[/fallback-value-error-custom-handler-default] – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.8-3 / test_header_field_sanitization – tests.contrib.sanic.sanic_tests
  • Name: Initializing / Test / Python-python-3.8-3 / test_custom_callback_handlers – tests.contrib.sanic.sanic_tests

🤖 GitHub comments

To re-run your PR in the CI, just comment with:

  • /test : Re-trigger the build.

@harshanarayana harshanarayana force-pushed the feature/GIT-521-sanic-apm-contrib branch 3 times, most recently from a45917f to 4a9c541 Compare March 6, 2021 18:00
@harshanarayana harshanarayana marked this pull request as ready for review March 6, 2021 18:19
@harshanarayana
Copy link
Contributor Author

Hi @beniwohli @basepi I would really appreciate it if you guys would take a look at this and see if things are going in the right direction for this PR.

Copy link
Contributor

@beniwohli beniwohli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@harshanarayana Great Work! Apart from a few small things, this looks great!

:param request: Sanic HTTP Request object
:return: string containing the Transaction name
"""
return f"{request.method} {request.path}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally try to get a parametrized version of the path (a.k.a "route") for the transaction name (so that /books/123 and /books/42 are tracked under the same transaction /books/<id> or similar).

Having a quick glance at the source code, request.app.router.get(request)[0].raw_path might be what we're looking for. Unfortunately, that triggers the resolver a second time, but there's an LRU cache on it, so the incurred overhead should be minimal. We might however want to catch the exceptions that Router._get raises.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me quickly test the difference in overhead caused by this change of moving from current to anything else that can get the url as /books/<id>. However, if you notice, there is a way to customize this behavior that is provided to the end user already using transaction_name_callback argument while creating the ElasticAPM instance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me use request.uri_template instead. This give me '/stuff/<info:int>' format for the URL. Do you think I should strip the :int or that is good to have ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am using request.uri_template in my custom instrumentation and it looks good. I would personally like to have param type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reopening this item back again. The uri_template has a small behavior that makes it not really suitable. I did a quick test to confirm my suspicion. It breaks the span generation workflow. Will find a better suitable alternative.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

        url_template = request.path
        # Sanic's new router puts this into the request itself so that it can be accessed easily
        if hasattr(request, "route"):
            url_template = request.route.path
        else:
            # Let us fallback to using old router model to extract the info
            try:
                _, _, _, url_template, _, _ = self._app.router.get(request=request)
            except:
                pass

        return f"{request.method} {url_template}"

Falling back to this way to make sure we are compatible with both version of sanic as the revamped router has changed a bit in how the data is accessed.

@ahopkins Does this look all right ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have the request object, why invoke the router again in the pre-21.3 block?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One quick thing worth mentioning, the request.route.path string will not have the first / in the path. Not sure if this matters for your usage.

@harshanarayana harshanarayana force-pushed the feature/GIT-521-sanic-apm-contrib branch from 3d516c7 to 6291aa9 Compare April 2, 2021 11:08
@harshanarayana harshanarayana requested a review from beniwohli April 2, 2021 14:34
@beniwohli
Copy link
Contributor

beniwohli commented Apr 7, 2021

@harshanarayana I ran the tests on our test suite. You can ignore the failures on Python 3.10 (there seems to be a compilation issue with httptools on that unreleased version of Python, see MagicStack/httptools#54), but the others look like legitimate failures:

https://apm-ci.elastic.co/blue/organizations/jenkins/apm-agent-python%2Fapm-agent-python-mbp/detail/PR-1056/26/tests

@harshanarayana
Copy link
Contributor Author

@harshanarayana I ran the tests on our test suite. You can ignore the failures on Python 3.10 (there seems to be a compilation issue with httptools on that unreleased version of Python, see MagicStack/httptools#54), but the others look like legitimate failures:

https://apm-ci.elastic.co/blue/organizations/jenkins/apm-agent-python%2Fapm-agent-python-mbp/detail/PR-1056/26/tests

Thanks a lot for the check @beniwohli Let me check and see what is broken and fix and update the PR.

@harshanarayana
Copy link
Contributor Author

@harshanarayana after excluding Python 3.6 (which we don't support when running async workloads due to the lack of contextvars), the tests now run correctly.

Is the PR ready to merge otherwise?

Sorry, @beniwohli I have been away again on some personal matters. I will rebase the changes again do a quick check with latest version of sanic and give you a go head by EOW for merge from my end,

@ajay1mg
Copy link

ajay1mg commented Aug 23, 2021

@harshanarayana what's the update here? is there anything pending on this one?

@ajay1mg
Copy link

ajay1mg commented Sep 23, 2021

@beniwohli what is the plan for this PR?

@basepi
Copy link
Contributor

basepi commented Sep 27, 2021

Hey @ajay1mg, sorry for the lack of response here. We're currently re-evaluating how we prioritize this kind of work.

Community contributions, especially of large features and integrations, are a bit fraught -- while they can seem like a slam-dunk, by accepting the contribution we are agreeing to support it into the future. So we need to make time to really check that it's solid and that we understand the underlying technologies before merging. Plus documentation! It's a lot of work that we need to actually roadmap and prioritize.

Thanks for your patience!

@AlexanderWert AlexanderWert added the community Issues opened by the community label Oct 7, 2021
@AlexanderWert AlexanderWert added this to the 8.0 milestone Oct 7, 2021
@soulcodex
Copy link

Any update about this merge? A lot of people is currently waiting this integration with SANIC to be more cleanest in the code and be in the same boat of elasticsearch APM implementations.

Thx

@basepi
Copy link
Contributor

basepi commented Oct 19, 2021

@soulcodex We have this on our roadmap. We need to spend the time to research Sanic for ourselves and make sure everything is good with this integration, since by merging this we'll be committing to maintaining it. Again, apologies for the long delay.

@soulcodex
Copy link

soulcodex commented Oct 19, 2021

@basepi i understand you but first understand a thousand of developers using SANIC for a lot of products for example RasaHQ and the last commit for this feature was 4 months ago :(

@ajaygupta2790
Copy link
Contributor

@harshanarayana after excluding Python 3.6 (which we don't support when running async workloads due to the lack of contextvars), the tests now run correctly.

Is the PR ready to merge otherwise?

I agree with @soulcodex, I personally use Sanic for my personal projects and know a lot of people using it. Also, if you look at the above comments, it was near ready to be merged.

@ahopkins
Copy link
Contributor

@basepi I am a maintainer of Sanic, and the original author of the PR is also a core developer of Sanic. Please LMK if you need any support from me or have any questions re: the project.

@basepi basepi self-assigned this Oct 27, 2021
@basepi
Copy link
Contributor

basepi commented Nov 1, 2021

/test

Copy link
Contributor

@basepi basepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My apologies for our long delays in reviewing this PR. It's an excellent addition! Couple of nits below and we'll get this tested and merged. 🎉

"SECRET_TOKEN": "supersecrettokenstuff",
})
Pass a pre-build Clinet instance to the APM Middleware::
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Pass a pre-build Clinet instance to the APM Middleware::
Pass a pre-build Client instance to the APM Middleware::

pytest-mock ; python_version >= '3.7'
httpx ; python_version >= '3.6'

sanic ; python_version >= '3.6'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be >= '3.7' instead? In the jenkins exclude you have excluded python 3.6.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is correct. Sanic does not support 3.6

include::./tornado.asciidoc[]

include::./starlette.asciidoc[]
include::./starlette.asciidoc[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
include::./starlette.asciidoc[]
include::./starlette.asciidoc[]
include::./sanic.asciidoc[]

@basepi
Copy link
Contributor

basepi commented Nov 1, 2021

Looks like a bunch of tests are failing (now that we're actually running them). I haven't looked at the failures yet -- please ping me if you have questions about the failures.

@basepi basepi removed the stretch label Nov 3, 2021
@basepi
Copy link
Contributor

basepi commented Nov 9, 2021

@harshanarayana Are you going to be able to look at these test failures? I'd love to get this fixed up and merged.

@ajaygupta2790
Copy link
Contributor

@ahopkins did anything changed/deprecated in sanic 21.9?
test cases are working fine till 21.6 by running ./tests/scripts/docker/run_tests.sh python-3.7.2 sanic-21.6 and having a new file reqs-sanic-21.6 with following requirements:
sanic==21.6
sanic-testing==0.7.0
-r reqs-base.txt

but breaks for 21.9 with following error:

================================================================================================= FAILURES =================================================================================================
___________________________________________________________________________________ test_get[/-GET /-1-custom_context0] ____________________________________________________________________________________

url = '/', transaction_name = 'GET /', span_count = 1, custom_context = {}, sanic_elastic_app = <function sanic_elastic_app.<locals>._generate at 0x7f8ca7fd1950>
elasticapm_client = <tests.fixtures.TempStoreClient object at 0x7f8ca80318d0>

    @pytest.mark.parametrize(
        "url, transaction_name, span_count, custom_context",
        [("/", "GET /", 1, {}),
         ("/greet/sanic", "GET /greet/<name:string>", 0, {"name": "sanic"})],
    )
    def test_get(url, transaction_name, span_count, custom_context, sanic_elastic_app, elasticapm_client):
>       sanic_app, apm = next(sanic_elastic_app(elastic_client=elasticapm_client))

tests/contrib/sanic/sanic_tests.py:46:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tests/contrib/sanic/fixtures.py:106: in _generate
    @app.exception(ValueError)
/home/user/.local/lib/python3.7/site-packages/sanic/mixins/exceptions.py:36: in decorator
    self._apply_exception_handler(future_exception)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = Sanic(name="elastic-apm-test-app")
handler = FutureException(handler=<function sanic_elastic_app.<locals>._generate.<locals>.handle_value_error at 0x7f8ca80cbc80>, exceptions=(<class 'ValueError'>,)), route_names = None

    def _apply_exception_handler(
        self,
        handler: FutureException,
        route_names: Optional[List[str]] = None,
    ):
        """Decorate a function to be registered as a handler for exceptions

        :param exceptions: exceptions
        :return: decorated function
        """

        for exception in handler.exceptions:
            if isinstance(exception, (tuple, list)):
                for e in exception:
                    self.error_handler.add(e, handler.handler, route_names)
            else:
>               self.error_handler.add(exception, handler.handler, route_names)
E               TypeError: add() takes 3 positional arguments but 4 were given

/home/user/.local/lib/python3.7/site-packages/sanic/app.py:356: TypeError

looks like something in registering a custom error handler?

@ahopkins
Copy link
Contributor

ahopkins commented Nov 9, 2021

looks like something in registering a custom error handler?

Yes, that is correct.

Usually, the fix is to just add: **kwargs.

I added something here recently as well: getsentry/sentry-python#1212

I can take a look at the tests to see if I can help with the same caveat I offered for Sentry: I do not know the product so I may need some help/guidance, and since I do not have write access to @harshanarayana repo, I guess I can either provide a diff, or make another PR?

@ajaygupta2790
Copy link
Contributor

I guess I can either provide a diff, or make another PR?
@basepi what do you suggest here?

@ahopkins
Copy link
Contributor

ahopkins commented Nov 9, 2021

Assuming it was that simple:

#1390

These were the only changes that I made:

diff --git a/docs/set-up.asciidoc b/docs/set-up.asciidoc
index 4df452e8..15269e0f 100644
--- a/docs/set-up.asciidoc
+++ b/docs/set-up.asciidoc
@@ -23,4 +23,6 @@ include::./tornado.asciidoc[]

 include::./starlette.asciidoc[]

+include::./sanic.asciidoc[]
+
 include::./serverless.asciidoc[]
diff --git a/elasticapm/contrib/sanic/patch.py b/elasticapm/contrib/sanic/patch.py
index 78c1bb2f..72986d59 100644
--- a/elasticapm/contrib/sanic/patch.py
+++ b/elasticapm/contrib/sanic/patch.py
@@ -50,11 +50,11 @@ class ElasticAPMPatchedErrorHandler(ErrorHandler):
         self._current_handler = current_handler  # type: ErrorHandler
         self._apm_handler = None  # type: ApmHandlerType

-    def add(self, exception, handler):
-        self._current_handler.add(exception, handler)
+    def add(self, exception, handler, *args, **kwargs):
+        self._current_handler.add(exception, handler, *args, **kwargs)

-    def lookup(self, exception):
-        return self._current_handler.lookup(exception)
+    def lookup(self, exception, *args, **kwargs):
+        return self._current_handler.lookup(exception, *args, **kwargs)

     def setup_apm_handler(self, apm_handler: ApmHandlerType, force: bool = False):
         if self._apm_handler is None or force:
diff --git a/elasticapm/contrib/sanic/__init__.py b/elasticapm/contrib/sanic/__init__.py
index 0d8b631b..991ce69d 100644
--- a/elasticapm/contrib/sanic/__init__.py
+++ b/elasticapm/contrib/sanic/__init__.py
@@ -86,7 +86,7 @@ class ElasticAPM:
         "SECRET_TOKEN": "supersecrettokenstuff",
     })

-    Pass a pre-build Clinet instance to the APM Middleware::
+    Pass a pre-build Client instance to the APM Middleware::

     >>> apm = ElasticAPM(app=app, client=Client())

diff --git a/setup.cfg b/setup.cfg
index 1f2c48e1..e6a9d938 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -96,7 +96,7 @@ tests_require =
     pytest-asyncio ; python_version >= '3.7'
     pytest-mock ; python_version >= '3.7'
     httpx ; python_version >= '3.6'
-    sanic ; python_version >= '3.6'
+    sanic ; python_version >= '3.7'

 [options.extras_require]
 flask =

@ajaygupta2790
Copy link
Contributor

that's all it took to pass the tests

@ajaygupta2790
Copy link
Contributor

These were the only changes that I made:

@basepi could you patch this PR with changes added by @ahopkins?

@basepi
Copy link
Contributor

basepi commented Nov 11, 2021

Closing in favor of #1390 which will merge shortly 🚀

@basepi basepi closed this Nov 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-python community Issues opened by the community

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Enable support for Sanic

8 participants